// D3D9_02 [Direct3D9 with FrameWindow].nova



// Using namespace declarations.
using Library.Direct3D9;
using Library.NFC;



// Custom Direct3D9 window class.
class Direct3D9WindowApp : FrameWindow
{
   // The Direct3D9 object.
   private Direct3D9 direct3D9;

   // The Direct3D present parameters.
   private D3DPresentParameters9 presentParameters;

   // The Direct3D device.
   private Direct3DDevice9 direct3DDevice9;

   // Define the custom vertex FVF value.
   private uint D3DFVF_CUSTOMVERTEX;

   // The vertex buffer.
   private Direct3DVertexBuffer9 vb;

   // The angle of the triangle (used for rotation).
   private float angle;

   // Resize backbuffer flag.
   private bool resizeBackbuffer;



   // Application class's "main" function.
   public static void main( String[] args )
   {
      // Create a new Direct3D9 window.
      Direct3D9WindowApp window = new Direct3D9WindowApp( "D3D9_02 [Direct3D9 with FrameWindow]", 640, 480 );

      // Show the window.
      window.show( true );

      // Process the window's events.
      window.processEvents( );
   }



   // Class constructor.
   private Direct3D9WindowApp( String title, int sizeX, int sizeY )
      : FrameWindow( title, sizeX, sizeY )
   {
      // Initialize the class's attributes.
      angle = 0;
      resizeBackbuffer = true;

      // Define a custom FVF.
      D3DFVF_CUSTOMVERTEX = Direct3D9.D3DFVF_XYZ | Direct3D9.D3DFVF_DIFFUSE;

      // Create the Direct3D9 object.
      direct3D9 = Direct3D9.direct3DCreate9( Direct3D9.D3D_SDK_VERSION );

      // Check for a null reference.
      if ( direct3D9 == null )
      {
         // Abort initialization.
         return;
      }

      // Create and initialize a new present parameters object.
      presentParameters = new D3DPresentParameters9( true,                             // Windowed.
                                                     Direct3D9.D3DSWAPEFFECT_DISCARD,  // Swap effect.
                                                     Direct3D9.D3DFMT_UNKNOWN );       // Back buffer format.

      // Create a new Direct3D device.
      direct3DDevice9 = direct3D9.createDevice( Direct3D9.D3DADAPTER_DEFAULT,                   // Adapter.
                                                Direct3D9.D3DDEVTYPE_HAL,                       // Device type.
                                                this,                                           // Focus window.
                                                Direct3D9.D3DCREATE_SOFTWARE_VERTEXPROCESSING,  // Behaviour flags.
                                                presentParameters );                            // Presentation parameters.

      // Check for a null reference.
      if ( direct3DDevice9 == null )
      {
         // Abort initialization.
         return;
      }

      // Initialize the geometry.
      initGeometry( );
   }



   // On paint event handler.
   public virtual void onPaint( )
   {
      // Render the scene.
      render( );
   }



   // On idle event handler.
   public virtual void onIdle( )
   {
      // Render the scene.
      render( );
   }



   // On size event handler.
   public virtual void onSize( int sizeX, int sizeY )
   {
      // Check the resize backbuffer flag.
      if ( resizeBackbuffer )
      {
         // Check for a null reference.
         if( vb != null )
         {
            // Release the vertex buffer object.
            vb.release( );
         }

         // Set the back buffer size.
         presentParameters.setBackBufferSize( (uint)sizeX, (uint)sizeY );

         // Reset the Direct3D device.
         direct3DDevice9.reset( presentParameters );

         // Initialize the geometry.
         initGeometry( );
      }
   }



   // On close event handler.
   public virtual void onClose( )
   {
      // Check for a null reference.
      if( vb != null )
      {
         // Release the vertex buffer object.
         vb.release( );
      }

      // Check for a null reference.
      if( direct3DDevice9 != null )
      {
         // Release the Direct3D device object.
         direct3DDevice9.release( );
      }

      // Check for a null reference.
      if( direct3D9 != null )
      {
         // Release the Direct3D9 object.
         direct3D9.release( );
      }
   }



   // Initialize the geometry.
   private bool initGeometry( )
   {
      // Turn off culling, so we see the front and back of the triangle.
      direct3DDevice9.setRenderState( Direct3DDevice9.D3DRS_CULLMODE, Direct3DDevice9.D3DCULL_NONE );

      // Turn off D3D lighting, since we are providing our own vertex colors.
      direct3DDevice9.setRenderState( Direct3DDevice9.D3DRS_LIGHTING, Direct3D9.FALSE );


      // Create the vertex buffer.
      vb = direct3DDevice9.createVertexBuffer( typeof( CustomVertexPosCol ),  // Type of vertex.
                                               3,                             // Number of vertices.
                                               0,                             // Usage.
                                               D3DFVF_CUSTOMVERTEX,           // Vertex format (FVF).
                                               Direct3D9.D3DPOOL_DEFAULT );   // Pool.

      // Lock the vertex buffer.
      Object[] vertices = vb.lock( 0, 0 );

      // Check for a null reference.
      if ( vertices == null )
      {
         // Return false for not initializing the geometry.
         return false;
      }


      // Initialize the vertices.
      // Left, red.
      vertices[ 0 ] = new CustomVertexPosCol( -1.0f, -1.0f, 0.0f, 0xffff0000 );

      // Right, green.
      vertices[ 1 ] = new CustomVertexPosCol( 1.0f, -1.0f, 0.0f, 0xff00ff00 );

      // Top, blue.
      vertices[ 2 ] = new CustomVertexPosCol( 0.0f, 1.0f, 0.0f, 0xff0000ff );

      // Unlock the vertex buffer.
      vb.unlock( );


      // Return true for success.
      return true;
   }



   // Render the scene.
   private bool render( )
   {
      // Clear the back buffer to black.
      direct3DDevice9.clear( Direct3D9.D3DCLEAR_TARGET,
                             Direct3D9.convertD3DCOLOR_XRGB( 0, 0, 0 ),
                             1.0f,
                             0 );

      // Begin the scene.
      if ( direct3DDevice9.beginScene( ) >= 0 )
      {
         // Setup the world, view, and projection Matrices.
         setupMatrices( );

         // Render the vertex buffer contents.
         direct3DDevice9.setStreamSource( 0, vb, 0 );
         direct3DDevice9.setFVF( D3DFVF_CUSTOMVERTEX );
         direct3DDevice9.drawPrimitive( Direct3D9.D3DPT_TRIANGLESTRIP, 0, 1 );

         // End the scene.
         direct3DDevice9.endScene( );
      }

      // Present the backbuffer contents to the display.
      direct3DDevice9.present( );


      // Return true for success.
      return true;
   }



   // Setup the world, view, and projection Matrices.
   private void setupMatrices( )
   {
      // For our world matrix, we will just rotate the object about the y-axis.
      angle += 0.01f;
      float[] matWorld = D3DX9.d3DXMatrixRotationY( angle );
      direct3DDevice9.setTransform( Direct3DDevice9.D3DTS_WORLD, matWorld );



      // Set up our view matrix. A view matrix can be defined given an eye point,
      // a point to lookat, and a direction for which way is up. Here, we set the
      // eye five units back along the z-axis and up three units, look at the
      // origin, and define "up" to be in the y-direction.
      float[] matView = D3DX9.d3DXMatrixLookAtLH( 0.0f, 3.0f, -5.0f,
                                                  0.0f, 0.0f,  0.0f,
                                                  0.0f, 1.0f,  0.0f );

      direct3DDevice9.setTransform( Direct3DDevice9.D3DTS_VIEW, matView );



      // For the projection matrix, we set up a perspective transform (which
      // transforms geometry from 3D view space to 2D viewport space, with
      // a perspective divide making objects smaller in the distance). To build
      // a perpsective transform, we need the field of view (1/4 pi is common),
      // the aspect ratio, and the near and far clipping planes (which define at
      // what distances geometry should be no longer be rendered).
      float[] matProj = D3DX9.d3DXMatrixPerspectiveFovLH( D3DX9.D3DX_PI / 4,
                                                          1.0f,
                                                          1.0f,
                                                          100.0f );

      direct3DDevice9.setTransform( Direct3DDevice9.D3DTS_PROJECTION, matProj );
   }
}